package com.zc.auth.security.core.access.meta;

import com.zc.commons.lang.exception.MsgHandlerException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.PathMatcher;

import javax.sql.DataSource;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 默认元数据管理
 *
 * @author zcc
 */
@CacheConfig(cacheNames = "defaultUrlRoleMetaData")
@Slf4j
public class DefaultUrlRoleMetaDataManager implements UrlRoleMetaDataManager {

    private static final String QUERY_SQL =
            "SELECT a.url_patten,b.role_code FROM system_url_role a INNER JOIN system_role b ON a.role_id = b.id WHERE a.server_name = ?";

    private PathMatcher pathMatcher = new AntPathMatcher();

    private String serverName;

    @Autowired
    private DataSource dataSource;

    public DefaultUrlRoleMetaDataManager(String serverName) {
        this.serverName = serverName;
    }

    @Cacheable(cacheNames = "defaultUrlRoleMetaData")
    @Override
    public Map<String, Set<String>> getUrlsAndRolesMap() {
        List<UrlPattenRoleEntity> list = queryPattenRole();
        Map<String, Set<String>> result = list.stream().collect(
                Collectors.groupingBy(UrlPattenRoleEntity::getUrlPatten,
                        Collectors.mapping(UrlPattenRoleEntity::getRoleCode, Collectors.toSet())));
        return result == null ? Collections.emptyMap() : result;
    }

    @CachePut(cacheNames = "defaultUrlRoleMetaData")
    @Override
    public Map<String, Set<String>> updateUrlsAndRolesMap() {
        List<UrlPattenRoleEntity> list = queryPattenRole();
        Map<String, Set<String>> result = list.stream().collect(
                Collectors.groupingBy(UrlPattenRoleEntity::getUrlPatten,
                        Collectors.mapping(UrlPattenRoleEntity::getRoleCode, Collectors.toSet())));
        return result == null ? Collections.emptyMap() : result;
    }

    @Override
    public Collection<String> getAccessibleRoles(String url) {
        return this.getAccessibleRoles(url, getUrlsAndRolesMap());
    }

    @Override
    public Collection<String> getAccessibleRoles(String url, Map<String, ? extends Collection<String>> map) {
        for (Map.Entry<String, ? extends Collection<String>> entry : map.entrySet()) {
            if (pathMatcher.match(entry.getKey(), url)) {
                return entry.getValue();
            }
        }
        return null;
    }

    /**
     * 从数据库查询
     *
     * @return
     * @throws SQLException
     */
    private List<UrlPattenRoleEntity> queryPattenRole() {
        List<UrlPattenRoleEntity> list = new ArrayList<>();
        PreparedStatement statement = null;
        try {
            statement = dataSource.getConnection().prepareStatement(QUERY_SQL);
            statement.setString(1, serverName);
            statement.execute();
            ResultSet resultSet = statement.getResultSet();
            if (resultSet != null) {
                while (resultSet.next()) {
                    UrlPattenRoleEntity entity = new UrlPattenRoleEntity();
                    entity.setUrlPatten(resultSet.getString(1));
                    entity.setRoleCode(resultSet.getString(2));
                    list.add(entity);
                }
            }
        } catch (SQLException e) {
            log.error("接口角色列表查询异常！", e);
            throw new MsgHandlerException("接口角色列表查询异常！");
        } finally {
            try {
                if (statement != null) {
                    statement.close();
                }
            } catch (SQLException ex) {
                log.error("statement未关闭", ex);
                throw new MsgHandlerException("接口角色列表查询statement未关闭！");
            }
        }
        return list;
    }
}
